
#include <BEvent>
#include <BPainter>
#include <BImage>
#include <BFont>
#include <BStyle>
#include <BStyle>
#include <BSizePolicy>

#include <BLabel>
#include "member_BLabel.h"
#include "member_BMovie.h"
#include "member_BWidget.h"

using namespace BWE;

#define member					(*(member_BLabel*)_ptr)
#define member_allocate()		_ptr = new member_BLabel(this)
#define member_release()		delete (member_BLabel*)_ptr

BLabel::BLabel(BWidget* parent) : BWidget(parent)
{
	member_allocate();
}
BLabel::BLabel(Form form, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setForm(form);
}
BLabel::BLabel(Form form, const BString& text, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setForm(form);
	setText(text);
}
BLabel::BLabel(const BString& text, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setText(text);
}
BLabel::BLabel(BImage* image, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setImage(image);
}
BLabel::BLabel(BImage* image, const BString& text, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setImage(image);
	setText(text);
}
BLabel::~BLabel()
{
	member_release();
}

void BLabel::copy(const BWidget* other)
{
	BWidget::copy(other);
	if (const BLabel* label = dynamic_cast<const BLabel*>(other))
	{
		member.text = label_member(label)->text;
		member.color = label_member(label)->color;
		member.image = label_member(label)->image;
		member.imageSize = label_member(label)->imageSize;
	}
}
BWidget* BLabel::clone() const
{
	BLabel* label = new BLabel();
	label->copy(this);
	return label;
}

void BLabel::setForm(Form form)
{
	if (member.alignment.ia_form != form)
	{
		member.alignment.ia_form = form;
		member.dirty = true;
		this->fresh();
	}
}
Form BLabel::form() const
{
	return member.alignment.ia_form;
}

void BLabel::setAlign(Align align)
{
	if (member.alignment.ia_align != align)
	{
		member.alignment.ia_align = align;
		member.dirty = true;
		if (this->checks(Signal_AlignChanged))
			emit(Signal_AlignChanged, align);
		this->fresh();
	}
}
Align BLabel::align() const
{
	return member.alignment.ia_align;
}

void BLabel::setSpacing(int spacing)
{
	if (member.alignment.ia_spacing < 0)
		member.alignment.ia_spacing = 0;
	if (member.alignment.ia_spacing > 1000)
		member.alignment.ia_spacing = 1000;
	if (member.alignment.ia_spacing != spacing)
	{
		member.alignment.ia_spacing = spacing;
		member.dirty = true;
		if (this->checks(Signal_SpacingChanged))
			this->emit(Signal_SpacingChanged, spacing);
		this->adjust();
		this->fresh();
	}
}
int BLabel::spacing() const
{
	return member.alignment.ia_spacing;
}

void BLabel::setColor(BByte r, BByte g, BByte b, BByte a)
{
	setColor(BColor(r, g, b, a));
}
void BLabel::setColor(const BColor& color)
{
	if (member.color != color)
	{
		member.color = color;
		if (this->checks(Signal_ColorChanged))
			this->emit(Signal_ColorChanged, color);
		this->fresh();
	}
}
const BColor& BLabel::color() const
{
	return member.color;
}

void BLabel::setText(const BString& text)
{
	if (member.text != text)
	{
		member.text = text;
		member.dirty = true;
		Policy widthPolicy = this->widthPolicy();
		Policy heightPolicy = this->heightPolicy();
		if (widthPolicy & Policy_Preferred || heightPolicy & Policy_Preferred)
		{
			this->adjust();
		}
		emit(Signal_TextChanged, member.text);
		this->fresh();
	}
}
const BString& BLabel::text() const
{
	return member.text;
}

void BLabel::setImage(BImage* image)
{
	if (member.image != image)
	{
		member.image = image;
		member.dirty = true;
		Policy widthPolicy = this->widthPolicy();
		Policy heightPolicy = this->heightPolicy();
		if (widthPolicy & Policy_Preferred || heightPolicy & Policy_Preferred)
		{
			this->adjust();
		}
		emit(Signal_ImageChanged, member.image);
		this->fresh();
	}
}
const BImage* BLabel::image() const
{
	return member.image;
}
BImage* BLabel::image()
{
	return member.image;
}

void BLabel::setImageSize(int imageWidth, int imageHeight)
{
	setImageSize(BSize(imageWidth, imageHeight));
}
void BLabel::setImageSize(const BSize& imageSize)
{
	if (member.imageSize != imageSize)
	{
		member.imageSize = imageSize;
		member.dirty = true;
		this->fresh();
	}
}
const BSize& BLabel::imageSize() const
{
	return member.imageSize;
}

BSize BLabel::sizeHint() const
{
	if (member.dirty)
	{
		member.freshRects();
		member.dirty = false;
	}
	return this->preferSize(member.contentSize);
}

bool BLabel::input(const BString& text, const BValue& value)
{
	if (text == "text")
	{
		setText(value);
		return true;
	}
	if (text == "color")
	{
		setColor(value);
		return true;
	}
	if (text == "image")
	{
		setImage(value);
		return true;
	}
	if (text == "image-size")
	{
		setImageSize(value);
		return true;
	}
	return BWidget::input(text, value);
}
bool BLabel::query(const BString& text, BValue& value) const
{
	if (text == "text")
	{
		value = member.text;
		return true;
	}
	if (text == "color")
	{
		value = member.color;
		return true;
	}
	if (text == "image")
	{
		value = member.image;
		return true;
	}
	if (text == "image-size")
	{
		value = member.imageSize;
		return true;
	}
	if (text == "content-rect")
	{
		value = member.alignment.ia_rect;
		return true;
	}
	if (text == "content-size")
	{
		value = member.alignment.ia_rect.size();
		return true;
	}
	if (text == "text-rect")
	{
		value = member.alignment.ia_textRect;
		return true;
	}
	if (text == "image-rect")
	{
		value = member.alignment.ia_iconRect;
		return true;
	}
	return BWidget::query(text, value);
}

void BLabel::resizeEvent(const BEvent& event)
{
	member.dirty = true;
}
void BLabel::updateEvent(const BEvent& event)
{
	if (BMovie* movie = member.image.as<BMovie>())
	{
		if (movie_member(movie)->dirty)
		{
			this->fresh();
		}
	}
}

void BLabel::styleEvent(const BEvent& event)
{
	const BStyle* style = this->realStyle();

	const BValue& textValue = style->value(Value_Text);
	if (textValue.valid())
		member.text = (BString&)textValue;

	const BValue& alignValue = style->value(Value_Align);
	if (alignValue.valid())
		member.alignment.ia_align = alignValue;

	const BValue& colorValue = style->value(Value_Color);
	if (colorValue.valid())
		member.color = colorValue;

	const BValue& imageValue = style->value(Value_Image);
	if (imageValue.valid())
		member.image = (BImage*)imageValue;

	const BValue& imageSizeValue = style->value(Value_Image_Size);
	if (imageSizeValue.valid())
		member.imageSize = imageSizeValue;

	member.dirty = true;
}
void BLabel::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.freshRects();
		member.dirty = false;
	}
}
void BLabel::paintEvent(const BEvent& event)
{
	BPainter painter(this);
	painter.drawBackground();
	painter.drawPerch();

	State state = painter.state();
	if (member.alignment.ia_iconRect.valid())
	{
		BImage* image = member.image;
		if (BIcon* icon = this->icon())
		{
			image = icon->image(painter.state());
		}
		if (image)
		{
			if (!painter.setColor(member.color))
				painter.setColor(Color_Text, state);
			painter.drawImage(member.alignment.ia_iconRect, member.image);
		}
	}

	if (member.text.size() && member.alignment.ia_textRect.valid())
	{
		if (painter.setColor(Color_Text, state))
		{
			if (member.t_text.size())
				painter.drawText(member.alignment.ia_textRect, member.t_text, member.alignment.ia_align);
			else
				painter.drawText(member.alignment.ia_textRect, member.text, member.alignment.ia_align);
		}
	}

	painter.drawMargin();
	painter.drawBorder();
}
